package com.xr.miniprogram.service.impl;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xr.common.constant.OrderStatusConstants;
import com.xr.common.enums.RedisDelayQueueEnum;
import com.xr.miniprogram.domain.*;
import com.xr.miniprogram.domain.vo.MiniProgramInsertOrderVO;
import com.xr.miniprogram.domain.vo.MiniProgramOrderVO;
import com.xr.miniprogram.mapper.*;
import com.xr.miniprogram.service.IMiniProgramOrderService;
import com.xr.miniprogram.tools.RedissonUtil.RedisDelayQueueUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * 订单配置Service业务层处理
 *
 * @author wls
 * @date 2023-09-01
 */
@Slf4j
@Service
public class MiniProgramOrderServiceImpl  extends ServiceImpl<MiniProgramOrderMapper, MiniProgramOrder> implements IMiniProgramOrderService {
    @Autowired
    private MiniProgramOrderMapper miniProgramOrderMapper;
    @Autowired
    private MiniProgramOrderUserMapper orderUserMapper;
    @Resource
    private MiniProgramCommentMapper commentMapper;
    @Autowired
    private RedisDelayQueueUtil redisDelayQueueUtil;
    @Resource
    private MiniProgramServiceLogMapper serviceLogMapper;
    @Resource
    private MiniProgramOrderMapper orderMapper;
    @Resource
    private MiniProgramServiceSnapshotMapper serviceSnapshotMapper;
    @Resource
    private MiniProgramStandardsSnapshotMapper standardsSnapshotMapper;
    @Resource
    private MiniProgramServiceMapper serviceMapper;
    @Resource
    private MiniProgramStandardsMapper standardsMapper;
    @Resource
    private MiniProgramStaffMapper staffMapper;

    @Transactional
    @Override
    public Object add(MiniProgramInsertOrderVO miniProgramInsertOrderVO) throws Exception {

        //构造订单
        MiniProgramOrder programOrder = miniProgramInsertOrderVO.toMiniProgramOrder();
        programOrder.setCreateTime(new Date());
        programOrder.setOrderNumber(this.createOrderNumber());//生成订单编号
        programOrder.setServiceSptVersion(miniProgramInsertOrderVO.getServiceVersion());
        programOrder.setStandardsSptVersion(miniProgramInsertOrderVO.getStandardsVersion());

        //订单快照处理 (服务详情与规格快照）
        this.handleOrderSnapshot(miniProgramInsertOrderVO);

        //设置订单状态为未支付
        programOrder.setOrderStatusId(OrderStatusConstants.WAITING_ORDER);
        orderMapper.insert(programOrder);

        //循环添加订单用户，一个订单可能对应多个订单用户状态
        //每个订单用户都有自己的服务日志 每个日志有对应的评论
        for (int i = 0; i < programOrder.getServiceNumSurplus(); i++) {
            //添加评论对象
            MiniProgramComment miniProgramComment= this.createComment(miniProgramInsertOrderVO, programOrder.getOrderId());
            commentMapper.insert(miniProgramComment);

            //添加日志对象
            MiniProgramServiceLog miniProgramServiceLog= this.createServiceLog(miniProgramComment);
            serviceLogMapper.insert(miniProgramServiceLog);

            //创建订单用户
            MiniProgramOrderUser miniProgramOrderUser = this.createOrderUser(miniProgramInsertOrderVO, programOrder, miniProgramServiceLog);
            if (i == 0) {
                miniProgramOrderUser.setServiceTime(miniProgramInsertOrderVO.getServiceTime());
            }
            orderUserMapper.insert(miniProgramOrderUser);
        }

        // 添加订单支付超时延迟队列
        redisDelayQueueUtil.addDelayQueue(programOrder.getOrderNumber(), 60*10, TimeUnit.SECONDS, RedisDelayQueueEnum.orderPaymentTimeout.getCode());

        return programOrder.getOrderId();
    }

    /**
     * 查询order
     *
     * @param orderId order主键
     * @return order
     */
    @Override
    public MiniProgramOrderVO selectMiniProgramOrderByOrderId(Long orderId) {
        return miniProgramOrderMapper.selectMiniProgramOrderByOrderId(orderId);
    }

    /**
     * 查询order列表
     *
     * @param miniProgramOrder order
     * @return order
     */
    @Override
    public IPage<MiniProgramOrderVO> selectMiniProgramOrderList(Page<MiniProgramOrderVO> page, MiniProgramOrder miniProgramOrder, Long statusCode, Long uStatusId, String staffName) {
        if(staffName == null){
            return miniProgramOrderMapper.selectMiniProgramOrderList(page,miniProgramOrder, statusCode, uStatusId, null);
        }
        MiniProgramStaff staff = staffMapper.selectOne(new QueryWrapper<MiniProgramStaff>().lambda().eq(MiniProgramStaff::getStaffName, staffName));
        if(staff != null){
            return miniProgramOrderMapper.selectMiniProgramOrderList(page,miniProgramOrder, statusCode, uStatusId, staff.getStaffId());
        }
        return miniProgramOrderMapper.selectMiniProgramOrderList(page,miniProgramOrder, statusCode, uStatusId, -1L);
    }

    @Override
    public MiniProgramOrder selectMiniProgramOrderByOrderNumber(String orderNumber) {
        return miniProgramOrderMapper.selectOne(new QueryWrapper<MiniProgramOrder>().lambda().eq(MiniProgramOrder::getOrderNumber, orderNumber));
    }

    /**
     * 查询超过时间未支付的订单
     * @param minutes
     * @return
     */
    @Override
    public List<MiniProgramOrder> getNoPay(int minutes) {
        LocalDateTime dateTime1 = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime localDateTime = dateTime1.minusMinutes(minutes);
        String format = localDateTime.format(formatter);
        return miniProgramOrderMapper.selectList(new QueryWrapper<MiniProgramOrder>().eq("order_status_id", OrderStatusConstants.WAITING_ORDER).le("create_time",format));
    }

    @Transactional
    @Override
    public void updateStatusByOrderNo(String orderNo, Long orderStatusId) {
        MiniProgramOrder miniProgramOrder = orderMapper.selectOne(new QueryWrapper<MiniProgramOrder>().eq("order_number", orderNo));
        if (orderStatusId.equals(OrderStatusConstants.SERVICE_ORDER)) {//指定状态为服务中，则: 1.代表支付成功处理 （待支付-->服务中)  2.代表取消退款处理 （退款审核中 --> 服务中）
            if(miniProgramOrder.getOrderStatusId().equals(OrderStatusConstants.WAITING_ORDER)) miniProgramOrder.setPayTime(new Date());//原订单状态为待支付
            miniProgramOrder.setOrderStatusId(orderStatusId);
            orderMapper.updateById(miniProgramOrder);
            List<MiniProgramOrderUser> miniProgramOrderUsers = orderUserMapper.selectList(new QueryWrapper<MiniProgramOrderUser>().eq("order_id", miniProgramOrder.getOrderId()));
            for (MiniProgramOrderUser miniProgramOrderUser : miniProgramOrderUsers) {
                miniProgramOrderUser.setOrderStatusId(OrderStatusConstants.PENDING_ORDER);
                orderUserMapper.updateById(miniProgramOrderUser);
            }
        }else {
            miniProgramOrder.setOrderStatusId(orderStatusId);
            orderMapper.updateById(miniProgramOrder);
            List<MiniProgramOrderUser> miniProgramOrderUsers = orderUserMapper.selectList(new QueryWrapper<MiniProgramOrderUser>().eq("order_id", miniProgramOrder.getOrderId()));
            for (MiniProgramOrderUser miniProgramOrderUser : miniProgramOrderUsers) {
                miniProgramOrderUser.setOrderStatusId(orderStatusId);
                orderUserMapper.updateById(miniProgramOrderUser);
            }
        }
    }

    /**
     * 订单快照处理
     */
    public void handleOrderSnapshot(MiniProgramInsertOrderVO miniProgramInsertOrderVO){
        MiniProgramServiceSnapshot serviceSnapshot = serviceSnapshotMapper.selectOne(new LambdaQueryWrapper<MiniProgramServiceSnapshot>()
                .eq(MiniProgramServiceSnapshot::getServiceId, miniProgramInsertOrderVO.getServiceId())
                .eq(MiniProgramServiceSnapshot::getServiceSptVersion, miniProgramInsertOrderVO.getServiceVersion()));
        MiniProgramStandardsSnapshot standardsSnapshot = standardsSnapshotMapper.selectOne(new LambdaQueryWrapper<MiniProgramStandardsSnapshot>()
                .eq(MiniProgramStandardsSnapshot::getStandardsId, miniProgramInsertOrderVO.getServiceStandardsId())
                .eq(MiniProgramStandardsSnapshot::getStandardsSptVersion, miniProgramInsertOrderVO.getStandardsVersion()));

        if(serviceSnapshot == null){//服务详情版本有更新
            MiniProgramServiceSnapshot newServiceSnapshot = new MiniProgramServiceSnapshot();
            newServiceSnapshot.setServiceId(miniProgramInsertOrderVO.getServiceId());
            newServiceSnapshot.setServiceSptVersion(miniProgramInsertOrderVO.getServiceVersion());
            newServiceSnapshot.setServiceSptContent(JSON.toJSONString(serviceMapper.selectById(miniProgramInsertOrderVO.getServiceId())));

            serviceSnapshotMapper.insert(newServiceSnapshot);
        }
        if(standardsSnapshot == null){//规格版本有更新
            MiniProgramStandardsSnapshot newStandardsSnapshot = new MiniProgramStandardsSnapshot();
            newStandardsSnapshot.setStandardsId(miniProgramInsertOrderVO.getServiceStandardsId());
            newStandardsSnapshot.setStandardsSptVersion(miniProgramInsertOrderVO.getStandardsVersion());
            newStandardsSnapshot.setStandardsSptContent(JSON.toJSONString(standardsMapper.selectById(miniProgramInsertOrderVO.getServiceStandardsId())));

            standardsSnapshotMapper.insert(newStandardsSnapshot);
        }
    }

    /**
     * 订单编号生成
     * @return
     */
    public String createOrderNumber(){
        long timestamp = new Date().getTime(); // 获取当前时间戳
        int randomNum = new Random().nextInt(1000); // 获取0-999之间的随机数
        return "WX" + timestamp + randomNum; // 拼接订单号
    }

    /**
     * 创建评论对象
     * @return
     */
    public MiniProgramComment createComment(MiniProgramInsertOrderVO miniProgramInsertOrderVO, Long orderId){
        MiniProgramComment miniProgramComment = new MiniProgramComment();
        miniProgramComment.setOrderId(orderId);
        miniProgramComment.setServiceId(miniProgramInsertOrderVO.getServiceId());
        miniProgramComment.setStandardsId(miniProgramInsertOrderVO.getServiceStandardsId());
        miniProgramComment.setMiniProgramUserId(miniProgramInsertOrderVO.getMiniProgramUserId());
        miniProgramComment.setRate(0L);
        return miniProgramComment;
    }

    /**
     * 创建日志对象
     * @param miniProgramComment
     * @return
     */
    public MiniProgramServiceLog createServiceLog(MiniProgramComment miniProgramComment){
        MiniProgramServiceLog serviceLog = new MiniProgramServiceLog();
        serviceLog.setMiniProgramCommentId(miniProgramComment.getMiniProgramCommentId());
        serviceLog.setStaffId(0L);
        serviceLog.setWorkStatus(0L);
        return serviceLog;
    }

    /**
     * 创建订单用户
     * @param miniProgramInsertOrderVO
     * @param miniProgramOrder
     * @param miniProgramServiceLog
     * @return
     */
    public MiniProgramOrderUser createOrderUser(MiniProgramInsertOrderVO miniProgramInsertOrderVO,MiniProgramOrder miniProgramOrder, MiniProgramServiceLog miniProgramServiceLog){
        MiniProgramOrderUser orderUser = new MiniProgramOrderUser();
        //获取订单地址
        MiniProgramUserAddress miniProgramUserAddress = miniProgramInsertOrderVO.getMiniProgramUserAddress();

        orderUser.setOrderNumber(miniProgramOrder.getOrderNumber());
        orderUser.setOrderAddress(this.getAddressString(miniProgramUserAddress));
        orderUser.setLocation(miniProgramUserAddress.getLocation());
        orderUser.setOrderStatusId(OrderStatusConstants.WAITING_ORDER);
        orderUser.setReceiver(miniProgramUserAddress.getReceiver());
        orderUser.setReceiverPhone(miniProgramUserAddress.getReceivePhone());
        orderUser.setOrderId(miniProgramOrder.getOrderId());
        orderUser.setCleanAreas(miniProgramInsertOrderVO.getCleanAreas());
        orderUser.setServiceLogId(miniProgramServiceLog.getServiceLogId());
        orderUser.setWorkTime(miniProgramInsertOrderVO.getWorkTime());
        return orderUser;
    }

    /**
     * 拼接地址字符串
     * @param miniProgramUserAddress
     * @return
     */
    public String getAddressString(MiniProgramUserAddress miniProgramUserAddress){
        String province = miniProgramUserAddress.getProvince();
        String municipality = miniProgramUserAddress.getMunicipality();
        String district = miniProgramUserAddress.getDistrict();
        String street = miniProgramUserAddress.getStreet();
        String addressName = miniProgramUserAddress.getAddressName();
        String detailAddress = miniProgramUserAddress.getDetailAddress();
        return province + municipality + district + "-" + addressName + detailAddress;
    }
}